#include <iostream>
#include <fstream>
#include <utility>
#include <vector>
#include <string>
#include "Config.hpp"

using namespace std;

Config::Config() :/*{{{*/
  configData(vector< pair< string, string > >())
{
  // do nothing
}/*}}}*/

Config::Config(string fileName) :/*{{{*/
  configData(vector< pair< string, string > >())
{
  this->parseFile(fileName);
}/*}}}*/

bool Config::parseFile(string fileName)/*{{{*/
{
  if (!this->openFile(fileName))
  {
    return false;
  };

  // while we don`t reach end of file
  while (!this->in.eof())
  {
    string line;
    int c;

    // get line by symbols
    while (!this->in.eof() && (c = this->in.get()) != '\n' && c != EOF)
    {
      line += static_cast< char >(c);
    }

    // strip comments in line
    this->stripComments(line);

    // if line is empty, skip it
    if (line.size() == 0)
    {
      continue;
    }

    // parse line
    if (!this->parseLine(line))
    {
      this->closeFile();
      return false;
    }
  }

  this->closeFile();
  return true;
}/*}}}*/

void Config::print() /*{{{*/
{
  for (unsigned int i = 0; i < this->configData.size(); ++i)
  {
    cout << this->configData[i].first << " -> [" << this->configData[i].second << "]" << endl;
  }
} /*}}}*/

void Config::clear()/*{{{*/
{
  this->configData.clear();
}/*}}}*/

string Config::getValue(string key)/*{{{*/
{
  for (unsigned int i = 0; i < this->configData.size(); ++i)
  {
    if (this->configData[i].first == key)
    {
      return this->configData[i].second;
    }
  }
  // if nothing found, return empty string
  return string();
}/*}}}*/

#ifdef QT_CORE_LIB
 QString Config::getValue(QString key)/*{{{*/
{
  for (unsigned int i = 0; i < this->configData.size(); ++i)
  {
    if (QString(this->configData[i].first.c_str()) == key)
    {
      return QString(this->configData[i].second.c_str());
    }
  }
  // if nothing found, return empty string
  return QString();
}/*}}}*/
#endif

bool Config::openFile(string fileName)/*{{{*/
{
  this->in.open(fileName.c_str());
  if (!this->in.is_open())
  {
    return false;
  }
  return true;
}/*}}}*/

void Config::closeFile()/*{{{*/
{
  this->in.clear();
  this->in.close();
}/*}}}*/

void Config::stripComments(string &str)/*{{{*/
{
  // strip comments
  string::size_type position = str.find("#");
  if (position != string::npos)
  {
    str.assign(str, 0, position);
  }
}/*}}}*/

void Config::stripSpaces(string &str)/*{{{*/
{
  // strip starting spaces
  unsigned int start;
  for (start = 0; start < str.size(); ++start)
  {
    if (str[start] != ' ' && str[start] != '\t')
    {
      break;
    }
  }
  str.assign(str, start, str.size() - start);

  // strip ending spaces
  unsigned int end;
  for (end = str.size(); end > 0; --end)
  {
    if (str[end - 1] != ' ' && str[end - 1] != '\t')
    {
      break;
    }
  }
  str.assign(str, 0, end);
}/*}}}*/

bool Config::parseLine(string line)/*{{{*/
{
  string::size_type pos = line.find("=");
  if (pos == string::npos)
  {
    return false;
  }
  string key = line.substr(0, pos);
  this->stripSpaces(key);
  string value = line.substr(pos + 1);
  this->stripSpaces(value);
  this->configData.push_back(pair< string, string >(key, value));
  return true;
}/*}}}*/
